package com.ytjj.common.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayOpenAuthTokenAppModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AppTokenExchangeSubElement;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ytjj.common.api.CommonResult;
import com.ytjj.common.constants.AlipayCertConstants;
import com.ytjj.common.constants.AlipayConstants;
import com.ytjj.common.constants.RedisConstants;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.model.YxAlipayConfig;
import com.ytjj.common.utils.AlipayUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.util.List;

/**
 * @Description 支付宝定时任务 订单校验
 *
 * @Version 1.0
 * 
 */

@Service
@Slf4j
public class AlipayService {
    @Autowired
    private AlipayConstants alipayConstants;
    @Autowired
    private AlipayUtil alipayUtil;
    @Autowired
    private AlipayCertConstants alipayCertConstants;
    @Autowired
    private RedisService redisService;

    /**
     * 支付宝 app订单查询
     *
     * @param outTradeNo
     * @return
     * @throws Exception
     */
    public AlipayTradeQueryResponse AliPayAppOrderQuery(String outTradeNo, String tradeNo) throws Exception {
        AlipayClient alipayClient = alipayUtil.getAlipayClient(null);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        log.info("支付宝app支付状态查询响应 订单号：{},response: {}", outTradeNo, JSONObject.toJSONString(response));
        return response;
    }

    /**
     * 支付宝 app订单查询
     * 证书模式
     * @param outTradeNo
     * @return
     * @throws Exception
     */
    public AlipayTradeQueryResponse AliPayAppOrderQueryByCert(String outTradeNo, String tradeNo) throws Exception {
        AlipayClient alipayClient = alipayUtil.getAlipayClientByCert();
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);

        String appAuthToken = redisService.get(RedisConstants.APPAUTHTOKEN_KEY + alipayCertConstants.getAPPID());
        if (StringUtils.isEmpty(appAuthToken)) {
            CommonResult refreshResult = appAuthTokenByAppId(alipayCertConstants.getAPPID());
            if (200 == refreshResult.getCode()) {
                appAuthToken = refreshResult.getData().toString();
            }
        }
        if (StringUtils.isEmpty(appAuthToken)) {
            throw new ApiException("支付失败，请稍后重试");
        }
        request.putOtherTextParam("app_auth_token", appAuthToken);//授权码
        AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
        log.info("支付宝app支付状态查询响应 订单号：{},response: {}", outTradeNo, JSONObject.toJSONString(response));
        return response;
    }

    /**
     * 支付宝退款
     *
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     */
    public AlipayTradeRefundResponse refundAliPayOrder(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
                                                       String refundDesc,String childId) throws AlipayApiException {
        log.info("支付宝退款开始------------>");

        AlipayClient alipayClient = alipayUtil.getAlipayClient(childId);
        AlipayTradeRefundResponse aliPayResponse = null;
        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setOutRequestNo(outRefundNo);
            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            model.setRefundReason(refundDesc);
            request.setBizModel(model);

//            String appAuthToken = redisService.get(RedisConstants.APPAUTHTOKEN_KEY + alipayCertConstants.getAPPID());
//            if (StringUtils.isEmpty(appAuthToken)) {
//                CommonResult refreshResult = appAuthTokenByAppId(alipayCertConstants.getAPPID());
//                if (200 == refreshResult.getCode()) {
//                    appAuthToken = refreshResult.getData().toString();
//                }
//            }
//            if (StringUtils.isEmpty(appAuthToken)) {
//                throw new ApiException("支付失败，请稍后重试");
//            }
//            request.putOtherTextParam("app_auth_token", appAuthToken);//授权码
//            aliPayResponse = alipayClient.certificateExecute(request);
            aliPayResponse = alipayClient.execute(request);
        }
        return aliPayResponse;
    }

    /**
     * 支付宝小程序退款
     *
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     */
    public AlipayTradeRefundResponse refundJsaApiAliPayOrder(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
                                                             String refundDesc,String childId) throws AlipayApiException {
        log.info("支付宝小程序退款开始------------>");

        AlipayClient alipayClient = alipayUtil.getJsApiAliPayClient(childId);
        AlipayTradeRefundResponse aliPayResponse = null;
        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("trade_no", outTradeNo);
            bizContent.put("refund_amount", new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            bizContent.put("out_request_no", outRefundNo);
            bizContent.put("refund_reason",refundDesc);
            request.setBizContent(bizContent.toString());
            aliPayResponse = alipayClient.execute(request);
        }
        log.info("支付宝小程序退款结束:{}------------>",JSONObject.toJSONString(aliPayResponse));
        return aliPayResponse;
    }

    /**
     * 商户2支付宝退款 临时方案备用
     *
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     */
    public AlipayTradeRefundResponse refundAliPayOrderOld(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
                                                       String refundDesc,String childId) throws AlipayApiException {
        log.info("支付宝退款开始------------>childId:{}",childId);

        AlipayClient alipayClient = alipayUtil.getAlipayClientOld(childId);
        AlipayTradeRefundResponse aliPayResponse = null;
        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setOutRequestNo(outRefundNo);
            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            model.setRefundReason(refundDesc);
            request.setBizModel(model);
            aliPayResponse = alipayClient.execute(request);
        }
        return aliPayResponse;
    }

    public AlipayTradeRefundResponse refundAliPayOrderMysql(String outTradeNo, String outRefundNo, Integer refundFee,
                                                            String refundDesc, YxAlipayConfig aliConfig) throws AlipayApiException {
        log.info("支付宝退款开始------------>aliConfig:{}", JSON.toJSONString(aliConfig));

        AlipayClient alipayClient = alipayUtil.getAlipayClientByMysql(aliConfig);
        AlipayTradeRefundResponse aliPayResponse = null;
        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setOutRequestNo(outRefundNo);
            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            model.setRefundReason(refundDesc);
            request.setBizModel(model);
            aliPayResponse = alipayClient.execute(request);
        }
        return aliPayResponse;
    }

    /**
     * 商户5支付宝退款 临时方案备用
     *
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     */
    public AlipayTradeRefundResponse refundAliPayOrder05(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
                                                          String refundDesc) throws AlipayApiException {
        log.info("支付宝退款开始------------>");

        AlipayClient alipayClient = alipayUtil.getAlipayClient05();
        AlipayTradeRefundResponse aliPayResponse = null;
        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setOutRequestNo(outRefundNo);
            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            model.setRefundReason(refundDesc);
            request.setBizModel(model);
            aliPayResponse = alipayClient.execute(request);
        }
        return aliPayResponse;
    }

    /**
     * 商户4支付宝退款 临时方案备用
     *
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     */
//    public AlipayTradeRefundResponse refundAliPayOrder04(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
//                                                         String refundDesc) throws AlipayApiException {
//        log.info("支付宝退款开始------------>");
//
//        AlipayClient alipayClient = alipayUtil.getAlipayClient04();
//        AlipayTradeRefundResponse aliPayResponse = null;
//        // 订单编号和支付宝交易号不能为空
//        if (outTradeNo != null && outRefundNo != null) {
//            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
//            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
//            model.setOutTradeNo(outTradeNo);
//            model.setOutRequestNo(outRefundNo);
//            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
//            model.setRefundReason(refundDesc);
//            request.setBizModel(model);
//            aliPayResponse = alipayClient.execute(request);
//        }
//        return aliPayResponse;
//    }

    /**
     * 支付宝退款-证书模式
     * @param outTradeNo
     * @param outRefundNo
     * @param totalFee
     * @param refundFee
     * @param refundDesc
     * @return
     * @throws AlipayApiException
     */
    public AlipayTradeRefundResponse refundAliPayOrderByCert(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee,
                                                             String refundDesc) throws AlipayApiException {
        log.info("支付宝退款开始-证书模式------------>");
        AlipayTradeRefundResponse aliPayResponse = null;
        AlipayClient alipayClient = alipayUtil.getAlipayClientByCert();
        if (null == alipayClient) {
            log.info("===初始化支付宝客户端异常===");
            throw new ApiException("系统异常，请稍后重试");
        }

        // 订单编号和支付宝交易号不能为空
        if (outTradeNo != null && outRefundNo != null) {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setOutRequestNo(outRefundNo);
            model.setRefundAmount(new BigDecimal(refundFee).divide(new BigDecimal(100)).setScale(2).toString());
            model.setRefundReason(refundDesc);
            request.setBizModel(model);

            String appAuthToken = redisService.get(RedisConstants.APPAUTHTOKEN_KEY + alipayCertConstants.getAPPID());
            if (StringUtils.isEmpty(appAuthToken)) {
                CommonResult refreshResult = appAuthTokenByAppId(alipayCertConstants.getAPPID());
                if (200 == refreshResult.getCode()) {
                    appAuthToken = refreshResult.getData().toString();
                }
            }
            if (StringUtils.isEmpty(appAuthToken)) {
                throw new ApiException("支付失败，请稍后重试");
            }
            request.putOtherTextParam("app_auth_token", appAuthToken);//授权码
            aliPayResponse = alipayClient.certificateExecute(request);
        }
        return aliPayResponse;
    }

    /**
     * 刷新app_auth_token
     * @param appId
     * @return
     * @throws AlipayApiException
     */
    public CommonResult appAuthTokenByAppId(@RequestParam("appId") String appId) throws AlipayApiException {
        String appAuthCode = redisService.get(RedisConstants.APPAUTHCODE_KEY + appId);
        if (StringUtils.isEmpty(appAuthCode)) {
            log.error("===获取appAuthCode失败==={}", appId);
            throw new ApiException("获取AppAuthCode失败");
        }
        String refreshToken = redisService.get(RedisConstants.APPREFRESHTOKEN_KEY + appId);
        if (StringUtils.isEmpty(refreshToken)) {
            log.error("===获取refreshToken失败==={}", appId);
            throw new ApiException("获取AppRefreshAuthToken失败");
        }

        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");  //gateway:支付宝网关（固定）https://openapi.alipay.com/gateway.do
        certAlipayRequest.setAppId(alipayCertConstants.getAPPID());  //APPID 即创建应用后生成,详情见创建应用并获取 APPID
        certAlipayRequest.setPrivateKey(alipayCertConstants.getRSA_PRIVATE_KEY());  //开发者应用私钥，由开发者自己生成
        certAlipayRequest.setFormat("json");  //参数返回格式，只支持 json 格式
        certAlipayRequest.setCharset("UTF8");  //请求和签名使用的字符编码格式，支持 GBK和 UTF-8
        certAlipayRequest.setSignType(alipayConstants.getSIGNTYPE());  //商户生成签名字符串所使用的签名算法类型，目前支持 RSA2 和 RSA，推荐商家使用 RSA2。
        certAlipayRequest.setCertPath(alipayCertConstants.getAPP_CERT_PATH()); //应用公钥证书路径（app_cert_path 文件绝对路径）
        certAlipayRequest.setAlipayPublicCertPath(alipayCertConstants.getALIPAY_CERT_PATH()); //支付宝公钥证书文件路径（alipay_cert_path 文件绝对路径）
        certAlipayRequest.setRootCertPath(alipayCertConstants.getALIPAY_ROOT_CERT_PATH());  //支付宝CA根证书文件路径（alipay_root_cert_path 文件绝对路径）
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);

        log.info("===alipay constants==={},{}", alipayConstants.getSIGNTYPE(), alipayCertConstants.getAPP_CERT_PATH());
        AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();
        AlipayOpenAuthTokenAppModel model = new AlipayOpenAuthTokenAppModel();
        model.setGrantType("refresh_token");//换码类型 authorization_code：使用 auth_code 换取令牌；refresh_token：使用刷新刷新令牌
//        model.setCode(appAuthCode);//授权码 grant_type= authorization_code 时，必须录入
        model.setRefreshToken(refreshToken);//刷新令牌
        request.setBizModel(model);
        try {
            AlipayOpenAuthTokenAppResponse response = alipayClient.certificateExecute(request);
            log.info("===appAuthTokenByAppId response==={}", JSONObject.toJSONString(response));
            String code = response.getCode();
            if (!"10000".equals(code)) {
                return CommonResult.failed();
            }
            List<AppTokenExchangeSubElement> tokens = response.getTokens();
            String appAuthToken_response = tokens.get(0).getAppAuthToken();
            String refreshToken_response = tokens.get(0).getAppRefreshToken();
            redisService.set(RedisConstants.APPAUTHTOKEN_KEY + appId, appAuthToken_response);
            redisService.expire(RedisConstants.APPAUTHTOKEN_KEY + appId, 364 * 24 * 60 * 60);//有效期364天
            redisService.set(RedisConstants.APPREFRESHTOKEN_KEY + appId, refreshToken_response);
            return CommonResult.success(appAuthToken_response);
        } catch (Exception e) {
            log.error("==={}===", e);
        }
        return CommonResult.failed();
    }
}

